#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>

#define PORT 80
#define BUFFER_SIZE 1024
#define WWW_DIR "/var/www/html"

// Function to read the content of a file
int read_file(const char *filepath, char *buffer, size_t buffer_size) {
    int fd = open(filepath, O_RDONLY);
    if (fd < 0) {
        return -1;  // File could not be opened
    }

    ssize_t bytes_read = read(fd, buffer, buffer_size - 1);  // Leave space for null terminator
    if (bytes_read < 0) {
        close(fd);
        return -1;  // Failed to read the file
    }

    buffer[bytes_read] = '\0';  // Null-terminate the buffer
    close(fd);
    return 0;  // Success
}

// Function to handle HTTP requests
void handle_request(int client_socket) {
    char buffer[BUFFER_SIZE];
    char method[BUFFER_SIZE], path[BUFFER_SIZE], version[BUFFER_SIZE];

    // Read the HTTP request
    read(client_socket, buffer, BUFFER_SIZE);
    sscanf(buffer, "%s %s %s", method, path, version);

    // Buffer to hold the file content
    char file_content[BUFFER_SIZE];
    const char *response;

    // Check for the requested file
    if (strcmp(path, "/") == 0 || strcmp(path, "/index.html") == 0) {
        if (read_file(WWW_DIR "/index.html", file_content, BUFFER_SIZE) == 0) {
            response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
            write(client_socket, response, strlen(response));
            write(client_socket, file_content, strlen(file_content));
        } else {
            response = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n<html><body><h1>404 Not Found</h1></body></html>";
            write(client_socket, response, strlen(response));
        }
    } else if (strcmp(path, "/post.html") == 0) {
        if (read_file(WWW_DIR "/post.html", file_content, BUFFER_SIZE) == 0) {
            response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n";
            write(client_socket, response, strlen(response));
            write(client_socket, file_content, strlen(file_content));
        } else {
            response = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n<html><body><h1>404 Not Found</h1></body></html>";
            write(client_socket, response, strlen(response));
        }
    } else {
        // Serve a default "Hello, World!" page for any other paths
        response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello, World!";
        write(client_socket, response, strlen(response));
    }

    // Close the connection
    close(client_socket);
}

// Daemonize the process
void daemonize() {
    pid_t pid;

    // Fork off the parent process
    pid = fork();

    // If we got a good PID, then we can exit the parent process.
    if (pid < 0) exit(EXIT_FAILURE);
    if (pid > 0) exit(EXIT_SUCCESS);

    // On success: The child process becomes the session leader.
    if (setsid() < 0) exit(EXIT_FAILURE);

    // Fork off for the second time
    pid = fork();

    // An error occurred
    if (pid < 0) exit(EXIT_FAILURE);

    // Success: Let the parent terminate.
    if (pid > 0) exit(EXIT_SUCCESS);

    // Set new file permissions
    umask(0);

    // Change the working directory to the root directory
    chdir("/");

    // Close all open file descriptors
    for (int x = sysconf(_SC_OPEN_MAX); x >= 0; x--) {
        close(x);
    }
}

// Main function
int main(int argc, char *argv[]) {
    int server_socket, client_socket;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    
    // Check if daemon mode is requested
    if (argc > 1 && strcmp(argv[1], "-d") == 0) {
        daemonize();
    }

    // Create a socket
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0) {
        perror("Socket creation failed");
        exit(EXIT_FAILURE);
    }

    // Set up the server address
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    // Bind the socket to the address and port
    if (bind(server_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        perror("Bind failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    // Start listening for connections
    if (listen(server_socket, 10) < 0) {
        perror("Listen failed");
        close(server_socket);
        exit(EXIT_FAILURE);
    }

    printf("Server is listening on port %d\n", PORT);

    // Handle incoming connections
    while (1) {
        client_socket = accept(server_socket, (struct sockaddr *)&client_addr, &client_addr_len);
        if (client_socket < 0) {
            perror("Accept failed");
            continue;
        }

        // Handle the client request
        handle_request(client_socket);
    }

    // Close the server socket
    close(server_socket);

    return 0;
}


